package com.kuaimacode.kframework.code.template;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.kuaimacode.kframework.code.domain.Field;
import com.kuaimacode.kframework.code.domain.Generate;
import com.kuaimacode.kframework.code.enums.FieldType;
import com.kuaimacode.kframework.code.utils.CodeUtil;
import com.kuaimacode.kframework.code.utils.GenerateUtil;
import com.kuaimacode.kframework.code.utils.TemplateUtil;
import com.kuaimacode.kframework.util.ToolUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;
import java.math.BigDecimal;
import java.nio.file.FileAlreadyExistsException;
import java.util.Date;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Administrator
 * @date 2018/10/23
 */
public class EntityTemplate {

    public String templateSuffix = "";

    /**
     * 生成类体
     */
    private static void genClazzBody(Generate Generate){
        //CodeUtil.annoBr(Entity.class);
        CodeUtil.append(CodeUtil.anno(TableName.class)).append("(\"").append(Generate.getBasic().
                getTablePrefix()).append(Generate.getBasic().getTableName()).append("\")").append(CodeUtil.lineBreak);
        CodeUtil.annoBr(Data.class);
        //CodeUtil.append(CodeUtil.anno(EntityListeners.class)).append("(").
        //        append(CodeUtil.clazz(AuditingEntityListener.class)).append(".class)").append(CodeUtil.lineBreak);
        CodeUtil.append("public class ").append(Generate.getBasic().getTableEntity()).append(" implements ").
                append(CodeUtil.clazz(Serializable.class)).append(" {").append(CodeUtil.lineBreak);

        CodeUtil.tabLineNo(1, CodeUtil.anno(TableField.class)
                + "(exist = false)" );
        CodeUtil.tabLineNo(1, "private static final long serialVersionUID = 1L;");

        Map<String, String> fieldType = ToolUtil.enumToMap(FieldType.class);
        for (Field field: Generate.getFields()) {
            genField(field, fieldType);
        }
        CodeUtil.lineNo("}");
    }

    /**
     * 生成类字段
     * @param field 字段对象
     */
    private static void genField(Field field, Map<String, String> fieldType){
        String type = fieldType.get(String.valueOf(field.getType()));
        switch (field.getName()){
            case "id":
                //CodeUtil.tabLineNo(1, CodeUtil.anno(Id.class));
                CodeUtil.tabLineNo(1, CodeUtil.anno(TableId.class)
                        + "(value = \"id\", type = " + CodeUtil.clazz(IdType.class) + ".AUTO)");
                CodeUtil.tabLineNo(1, "private " + type + " id;");
                break;
            /*case "createAt":
                CodeUtil.tabLineNo(1, "// " + field.getTitle());
                CodeUtil.tabLineNo(1, CodeUtil.anno(CreatedDate.class));
                CodeUtil.tabLineNo(1, "private " + CodeUtil.clazz(Date.class) + " createAt;");
                break;
            case "updateAt":
                CodeUtil.tabLineNo(1, "// " + field.getTitle());
                CodeUtil.tabLineNo(1, CodeUtil.anno(LastModifiedDate.class));
                CodeUtil.tabLineNo(1, "private " + CodeUtil.clazz(Date.class) + " updateAt;");
                break;
            case "createBy":
                CodeUtil.tabLineNo(1, "// " + field.getTitle());
                CodeUtil.tabLineNo(1, CodeUtil.anno(CreatedBy.class));
                CodeUtil.tabLineNo(1, CodeUtil.anno(ManyToOne.class)
                        + "(fetch="+ CodeUtil.clazz(FetchType.class) +".LAZY)");
                CodeUtil.tabLineNo(1, CodeUtil.anno(JoinColumn.class) + "(name=\"create_by\")");
                CodeUtil.tabLineNo(1, CodeUtil.anno(JsonIgnore.class));
                //CodeUtil.tabLineNo(1, "private " + CodeUtil.clazz(User.class) + " createBy;");
                break;
            case "updateBy":
                CodeUtil.tabLineNo(1, "// " + field.getTitle());
                CodeUtil.tabLineNo(1, CodeUtil.anno(LastModifiedBy.class));
                CodeUtil.tabLineNo(1, CodeUtil.anno(ManyToOne.class)
                        + "(fetch="+ CodeUtil.clazz(FetchType.class) +".LAZY)");
                CodeUtil.tabLineNo(1, CodeUtil.anno(JoinColumn.class) + "(name=\"update_by\")");
                CodeUtil.tabLineNo(1, CodeUtil.anno(JsonIgnore.class));
                //CodeUtil.tabLineNo(1, "private " + CodeUtil.clazz(User.class) + " updateBy;");
                break;
            case "status":
                CodeUtil.tabLineNo(1, "// " + field.getTitle());
                CodeUtil.tabLineNo(1, "private Byte status = " + CodeUtil.clazz(StatusEnum.class) + ".OK.getCode();");
                break;*/
            default:
//                if(type.equals(FieldType.Text.getMessage())){
//                    CodeUtil.tabLineNo(1, CodeUtil.anno(Lob.class) + " " + CodeUtil.anno(Column.class) + "(columnDefinition=\"TEXT\")");
//                }
                //CodeUtil.tabLineNo(1, "// " + field.getTitle());
                CodeUtil.tabLineNo(1, CodeUtil.anno(ApiModelProperty.class)
                        + "(value = \""+field.getTitle()+"\")");
                CodeUtil.tabLineNo(1, CodeUtil.anno(TableField.class)
                        + "(\""+upperCharToUnderLine(field.getName())+"\")");
                CodeUtil.tabLine(1, "private " + type + " " + field.getName());
        }
    }

    /**
     * 生成实体类模板
     */
    public static String generate(Generate generate) {
        CodeUtil.create();
        CodeUtil.setPackageName("package com.kuaimacode.kframework.mybatis.models."+generate.getBasic().getGenModule()+ ";");
        //CodeUtil.setPackageName(TemplateUtil.getPackage(generate, "domain"));
        CodeUtil.importLine(IdType.class);
        CodeUtil.importLine(TableField.class);
        CodeUtil.importLine(TableId.class);
        CodeUtil.importLine(TableName.class);
        CodeUtil.importLine(Data.class);
        CodeUtil.importLine(BigDecimal.class);
        CodeUtil.importLine(Date.class);
        //CodeUtil.addImportAll("javax.persistence");
        TemplateUtil.genAuthor(generate);
        EntityTemplate.genClazzBody(generate);

        // 生成文件
        String filePath = GenerateUtil.getJavaFilePath(generate, "domain", "");
        //处理路径问题
        filePath = filePath.replace("/admin/src/main","/core/src/main").replaceAll("/admin/.*/domain", "/mybatis/models/"+generate.getBasic().getGenModule());
        try {
            GenerateUtil.generateFile(filePath, CodeUtil.save());
        } catch (FileAlreadyExistsException e) {
            return GenerateUtil.fileExist(filePath);
        }
        return filePath;
    }

    /**
     * 字符串大写字母转下划线
     * @param param
     * @return
     */
    public static String upperCharToUnderLine(String param) {
        Pattern  p= Pattern.compile("[A-Z]");
        if(param==null ||param.equals("")){
            return "";
        }
        StringBuilder builder=new StringBuilder(param);
        Matcher mc=p.matcher(param);
        int i=0;
        while (mc.find()) {
            builder.replace(mc.start()+i, mc.end()+i, "_"+mc.group().toLowerCase());
            i++;
        }

        if('_' == builder.charAt(0)){
            builder.deleteCharAt(0);
        }
        return builder.toString();
    }

}
